#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import tkinter as tk
from tkinter import ttk, messagebox, scrolledtext
import subprocess
import os
import re
import shutil
import tempfile

# 版本信息
KM_VERSION = "1.1.199"

class PackageManager:
    """包管理器类"""
    def __init__(self):
        self.package_manager = self._detect_package_manager()
        
    def _detect_package_manager(self):
        """通过检测可用的包管理器来确定系统类型"""
        # 检测 apt (Debian/Ubuntu 系列)
        if shutil.which('apt-get'):
            return 'apt'
        # 检测 dnf (Fedora/CentOS/RHEL 系列)

        elif shutil.which('dnf'):
            return 'dnf'
        # 检测 pacman (Arch Linux 系列)
        elif shutil.which('pacman'):
            return 'pacman'
        # 检测 yum (旧版 CentOS/RHEL)
        elif shutil.which('yum'):
            return 'yum'
        # 检测 zypper (openSUSE)
        elif shutil.which('zypper'):
            return 'zypper'
        else:
            raise RuntimeError("无法检测到支持的包管理器")
            
    def get_package_names(self, kernel_version, action='install'):
        """根据包管理器和操作类型生成相关的包名列表"""
        packages = []
        
        if self.package_manager == 'apt':
            if action == 'install':
                packages.extend([
                    f'linux-image-{kernel_version}',
                    f'linux-headers-{kernel_version}',
                ])
            else:  # remove
                packages.extend([
                    f'linux-image-{kernel_version}',
                    f'linux-headers-{kernel_version}',
                ])
        elif self.package_manager in ['dnf', 'yum']:
            if action == 'install':
                packages.extend([
                    f'kernel-{kernel_version}',
                    f'kernel-headers-{kernel_version}',
                    f'kernel-devel-{kernel_version}',
                ])
            else:  # remove
                packages.extend([
                    f'kernel-{kernel_version}',
                    f'kernel-headers-{kernel_version}',
                    f'kernel-devel-{kernel_version}',
                ])
        elif self.package_manager == 'pacman':
            if action == 'install':
                packages.extend([
                    f'linux-{kernel_version}',
                    f'linux-headers-{kernel_version}',
                ])
            else:  # remove
                packages.extend([
                    f'linux-{kernel_version}',
                    f'linux-headers-{kernel_version}',
                ])
        elif self.package_manager == 'zypper':
            if action == 'install':
                packages.extend([
                    f'kernel-{kernel_version}',
                    f'kernel-devel-{kernel_version}',
                ])
            else:  # remove
                packages.extend([
                    f'kernel-{kernel_version}',
                    f'kernel-devel-{kernel_version}',
                ])
        else:
            raise RuntimeError(f"不支持的包管理器: {self.package_manager}")
            
        return packages
    
    def install_packages(self, package_names, log_window=None):
        """安装多个包"""
        self._install_package_list(package_names, log_window)
        return package_names
    
    def remove_packages(self, package_names, log_window=None):
        """移除多个包"""
        self._remove_package_list(package_names, log_window)
    
    def _install_package_list(self, package_names, log_window=None):
        """安装包列表"""
        try:
            if self.package_manager == 'apt':
                if os.geteuid() != 0:
                    try:
                        if log_window:
                            log_window.add_log("使用 pkexec 执行安装命令...")
                        result = subprocess.Popen(['pkexec', 'apt-get', 'install', '-y'] + package_names, 
                                                stdout=subprocess.PIPE, stderr=subprocess.PIPE, 
                                                universal_newlines=True)
                        # 实时读取输出
                        for line in iter(result.stdout.readline, ''):
                            if log_window:
                                log_window.add_log(line.rstrip())
                        for line in iter(result.stderr.readline, ''):
                            if log_window:
                                log_window.add_log("错误: " + line.rstrip())
                        result.wait()
                        if result.returncode != 0:
                            raise subprocess.CalledProcessError(result.returncode, result.args)
                    except (subprocess.CalledProcessError, FileNotFoundError):
                        try:
                            if log_window:
                                log_window.add_log("使用 sudo 执行安装命令...")
                            result = subprocess.Popen(['sudo', 'apt-get', 'install', '-y'] + package_names,
                                                    stdout=subprocess.PIPE, stderr=subprocess.PIPE, 
                                                    universal_newlines=True)
                            # 实时读取输出
                            for line in iter(result.stdout.readline, ''):
                                if log_window:
                                    log_window.add_log(line.rstrip())
                            for line in iter(result.stderr.readline, ''):
                                if log_window:
                                    log_window.add_log("错误: " + line.rstrip())
                            result.wait()
                            if result.returncode != 0:
                                raise subprocess.CalledProcessError(result.returncode, result.args)
                        except (subprocess.CalledProcessError, FileNotFoundError):
                            raise PermissionError("无法安装包")
                else:
                    if log_window:
                        log_window.add_log("以 root 权限执行安装命令...")
                    result = subprocess.Popen(['apt-get', 'install', '-y'] + package_names, 
                                            stdout=subprocess.PIPE, stderr=subprocess.PIPE, 
                                            universal_newlines=True)
                    # 实时读取输出
                    for line in iter(result.stdout.readline, ''):
                        if log_window:
                            log_window.add_log(line.rstrip())
                    for line in iter(result.stderr.readline, ''):
                        if log_window:
                            log_window.add_log("错误: " + line.rstrip())
                    result.wait()
                    if result.returncode != 0:
                        raise subprocess.CalledProcessError(result.returncode, result.args)
                        
            elif self.package_manager in ['dnf', 'yum']:
                cmd = 'dnf' if self.package_manager == 'dnf' else 'yum'
                if os.geteuid() != 0:
                    try:
                        if log_window:
                            log_window.add_log(f"使用 pkexec 执行安装命令...")
                        result = subprocess.Popen(['pkexec', cmd, 'install', '-y'] + package_names,
                                                stdout=subprocess.PIPE, stderr=subprocess.PIPE, 
                                                universal_newlines=True)
                        # 实时读取输出
                        for line in iter(result.stdout.readline, ''):
                            if log_window:
                                log_window.add_log(line.rstrip())
                        for line in iter(result.stderr.readline, ''):
                            if log_window:
                                log_window.add_log("错误: " + line.rstrip())
                        result.wait()
                        if result.returncode != 0:
                            raise subprocess.CalledProcessError(result.returncode, result.args)
                    except (subprocess.CalledProcessError, FileNotFoundError):
                        try:
                            if log_window:
                                log_window.add_log(f"使用 sudo 执行安装命令...")
                            result = subprocess.Popen(['sudo', cmd, 'install', '-y'] + package_names,
                                                    stdout=subprocess.PIPE, stderr=subprocess.PIPE, 
                                                    universal_newlines=True)
                            # 实时读取输出
                            for line in iter(result.stdout.readline, ''):
                                if log_window:
                                    log_window.add_log(line.rstrip())
                            for line in iter(result.stderr.readline, ''):
                                if log_window:
                                    log_window.add_log("错误: " + line.rstrip())
                            result.wait()
                            if result.returncode != 0:
                                raise subprocess.CalledProcessError(result.returncode, result.args)
                        except (subprocess.CalledProcessError, FileNotFoundError):
                            raise PermissionError("无法安装包")
                else:
                    if log_window:
                        log_window.add_log("以 root 权限执行安装命令...")
                    result = subprocess.Popen([cmd, 'install', '-y'] + package_names, 
                                            stdout=subprocess.PIPE, stderr=subprocess.PIPE, 
                                            universal_newlines=True)
                    # 实时读取输出
                    for line in iter(result.stdout.readline, ''):
                        if log_window:
                            log_window.add_log(line.rstrip())
                    for line in iter(result.stderr.readline, ''):
                        if log_window:
                            log_window.add_log("错误: " + line.rstrip())
                    result.wait()
                    if result.returncode != 0:
                        raise subprocess.CalledProcessError(result.returncode, result.args)
                        
            elif self.package_manager == 'pacman':
                if os.geteuid() != 0:
                    try:
                        if log_window:
                            log_window.add_log("使用 pkexec 执行安装命令...")
                        result = subprocess.Popen(['pkexec', 'pacman', '-S', '--noconfirm'] + package_names,
                                                stdout=subprocess.PIPE, stderr=subprocess.PIPE, 
                                                universal_newlines=True)
                        # 实时读取输出
                        for line in iter(result.stdout.readline, ''):
                            if log_window:
                                log_window.add_log(line.rstrip())
                        for line in iter(result.stderr.readline, ''):
                            if log_window:
                                log_window.add_log("错误: " + line.rstrip())
                        result.wait()
                        if result.returncode != 0:
                            raise subprocess.CalledProcessError(result.returncode, result.args)
                    except (subprocess.CalledProcessError, FileNotFoundError):
                        try:
                            if log_window:
                                log_window.add_log("使用 sudo 执行安装命令...")
                            result = subprocess.Popen(['sudo', 'pacman', '-S', '--noconfirm'] + package_names,
                                                    stdout=subprocess.PIPE, stderr=subprocess.PIPE, 
                                                    universal_newlines=True)
                            # 实时读取输出
                            for line in iter(result.stdout.readline, ''):
                                if log_window:
                                    log_window.add_log(line.rstrip())
                            for line in iter(result.stderr.readline, ''):
                                if log_window:
                                    log_window.add_log("错误: " + line.rstrip())
                            result.wait()
                            if result.returncode != 0:
                                raise subprocess.CalledProcessError(result.returncode, result.args)
                        except (subprocess.CalledProcessError, FileNotFoundError):
                            raise PermissionError("无法安装包")
                else:
                    if log_window:
                        log_window.add_log("以 root 权限执行安装命令...")
                    result = subprocess.Popen(['pacman', '-S', '--noconfirm'] + package_names, 
                                            stdout=subprocess.PIPE, stderr=subprocess.PIPE, 
                                            universal_newlines=True)
                    # 实时读取输出
                    for line in iter(result.stdout.readline, ''):
                        if log_window:
                            log_window.add_log(line.rstrip())
                    for line in iter(result.stderr.readline, ''):
                        if log_window:
                            log_window.add_log("错误: " + line.rstrip())
                    result.wait()
                    if result.returncode != 0:
                        raise subprocess.CalledProcessError(result.returncode, result.args)
                        
            elif self.package_manager == 'zypper':
                if os.geteuid() != 0:
                    try:
                        if log_window:
                            log_window.add_log("使用 pkexec 执行安装命令...")
                        result = subprocess.Popen(['pkexec', 'zypper', 'install', '-y'] + package_names,
                                                stdout=subprocess.PIPE, stderr=subprocess.PIPE, 
                                                universal_newlines=True)
                        # 实时读取输出
                        for line in iter(result.stdout.readline, ''):
                            if log_window:
                                log_window.add_log(line.rstrip())
                        for line in iter(result.stderr.readline, ''):
                            if log_window:
                                log_window.add_log("错误: " + line.rstrip())
                        result.wait()
                        if result.returncode != 0:
                            raise subprocess.CalledProcessError(result.returncode, result.args)
                    except (subprocess.CalledProcessError, FileNotFoundError):
                        try:
                            if log_window:
                                log_window.add_log("使用 sudo 执行安装命令...")
                            result = subprocess.Popen(['sudo', 'zypper', 'install', '-y'] + package_names,
                                                    stdout=subprocess.PIPE, stderr=subprocess.PIPE, 
                                                    universal_newlines=True)
                            # 实时读取输出
                            for line in iter(result.stdout.readline, ''):
                                if log_window:
                                    log_window.add_log(line.rstrip())
                            for line in iter(result.stderr.readline, ''):
                                if log_window:
                                    log_window.add_log("错误: " + line.rstrip())
                            result.wait()
                            if result.returncode != 0:
                                raise subprocess.CalledProcessError(result.returncode, result.args)
                        except (subprocess.CalledProcessError, FileNotFoundError):
                            raise PermissionError("无法安装包")
                else:
                    if log_window:
                        log_window.add_log("以 root 权限执行安装命令...")
                    result = subprocess.Popen(['zypper', 'install', '-y'] + package_names, 
                                            stdout=subprocess.PIPE, stderr=subprocess.PIPE, 
                                            universal_newlines=True)
                    # 实时读取输出
                    for line in iter(result.stdout.readline, ''):
                        if log_window:
                            log_window.add_log(line.rstrip())
                    for line in iter(result.stderr.readline, ''):
                        if log_window:
                            log_window.add_log("错误: " + line.rstrip())
                    result.wait()
                    if result.returncode != 0:
                        raise subprocess.CalledProcessError(result.returncode, result.args)
                        
        except Exception as e:
            raise RuntimeError(f"安装包失败: {str(e)}")
    
    def _remove_package_list(self, package_names, log_window=None):
        """移除包列表"""
        try:
            if self.package_manager == 'apt':
                if os.geteuid() != 0:
                    try:
                        if log_window:
                            log_window.add_log("使用 pkexec 执行移除命令...")
                        result = subprocess.Popen(['pkexec', 'apt-get', 'remove', '-y'] + package_names, 
                                                stdout=subprocess.PIPE, stderr=subprocess.PIPE, 
                                                universal_newlines=True)
                        # 实时读取输出
                        for line in iter(result.stdout.readline, ''):
                            if log_window:
                                log_window.add_log(line.rstrip())
                        for line in iter(result.stderr.readline, ''):
                            if log_window:
                                log_window.add_log("错误: " + line.rstrip())
                        result.wait()
                        if result.returncode != 0:
                            raise subprocess.CalledProcessError(result.returncode, result.args)
                    except (subprocess.CalledProcessError, FileNotFoundError):
                        try:
                            if log_window:
                                log_window.add_log("使用 sudo 执行移除命令...")
                            result = subprocess.Popen(['sudo', 'apt-get', 'remove', '-y'] + package_names,
                                                    stdout=subprocess.PIPE, stderr=subprocess.PIPE, 
                                                    universal_newlines=True)
                            # 实时读取输出
                            for line in iter(result.stdout.readline, ''):
                                if log_window:
                                    log_window.add_log(line.rstrip())
                            for line in iter(result.stderr.readline, ''):
                                if log_window:
                                    log_window.add_log("错误: " + line.rstrip())
                            result.wait()
                            if result.returncode != 0:
                                raise subprocess.CalledProcessError(result.returncode, result.args)
                        except (subprocess.CalledProcessError, FileNotFoundError):
                            raise PermissionError("无法移除包")
                else:
                    if log_window:
                        log_window.add_log("以 root 权限执行移除命令...")
                    result = subprocess.Popen(['apt-get', 'remove', '-y'] + package_names, 
                                            stdout=subprocess.PIPE, stderr=subprocess.PIPE, 
                                            universal_newlines=True)
                    # 实时读取输出
                    for line in iter(result.stdout.readline, ''):
                        if log_window:
                            log_window.add_log(line.rstrip())
                    for line in iter(result.stderr.readline, ''):
                        if log_window:
                            log_window.add_log("错误: " + line.rstrip())
                    result.wait()
                    if result.returncode != 0:
                        raise subprocess.CalledProcessError(result.returncode, result.args)
                        
            elif self.package_manager in ['dnf', 'yum']:
                cmd = 'dnf' if self.package_manager == 'dnf' else 'yum'
                if os.geteuid() != 0:
                    try:
                        if log_window:
                            log_window.add_log(f"使用 pkexec 执行移除命令...")
                        result = subprocess.Popen(['pkexec', cmd, 'remove', '-y'] + package_names,
                                                stdout=subprocess.PIPE, stderr=subprocess.PIPE, 
                                                universal_newlines=True)
                        # 实时读取输出
                        for line in iter(result.stdout.readline, ''):
                            if log_window:
                                log_window.add_log(line.rstrip())
                        for line in iter(result.stderr.readline, ''):
                            if log_window:
                                log_window.add_log("错误: " + line.rstrip())
                        result.wait()
                        if result.returncode != 0:
                            raise subprocess.CalledProcessError(result.returncode, result.args)
                    except (subprocess.CalledProcessError, FileNotFoundError):
                        try:
                            if log_window:
                                log_window.add_log(f"使用 sudo 执行移除命令...")
                            result = subprocess.Popen(['sudo', cmd, 'remove', '-y'] + package_names,
                                                    stdout=subprocess.PIPE, stderr=subprocess.PIPE, 
                                                    universal_newlines=True)
                            # 实时读取输出
                            for line in iter(result.stdout.readline, ''):
                                if log_window:
                                    log_window.add_log(line.rstrip())
                            for line in iter(result.stderr.readline, ''):
                                if log_window:
                                    log_window.add_log("错误: " + line.rstrip())
                            result.wait()
                            if result.returncode != 0:
                                raise subprocess.CalledProcessError(result.returncode, result.args)
                        except (subprocess.CalledProcessError, FileNotFoundError):
                            raise PermissionError("无法移除包")
                else:
                    if log_window:
                        log_window.add_log("以 root 权限执行移除命令...")
                    result = subprocess.Popen([cmd, 'remove', '-y'] + package_names, 
                                            stdout=subprocess.PIPE, stderr=subprocess.PIPE, 
                                            universal_newlines=True)
                    # 实时读取输出
                    for line in iter(result.stdout.readline, ''):
                        if log_window:
                            log_window.add_log(line.rstrip())
                    for line in iter(result.stderr.readline, ''):
                        if log_window:
                            log_window.add_log("错误: " + line.rstrip())
                    result.wait()
                    if result.returncode != 0:
                        raise subprocess.CalledProcessError(result.returncode, result.args)
                        
            elif self.package_manager == 'pacman':
                if os.geteuid() != 0:
                    try:
                        if log_window:
                            log_window.add_log("使用 pkexec 执行移除命令...")
                        result = subprocess.Popen(['pkexec', 'pacman', '-R', '--noconfirm'] + package_names,
                                                stdout=subprocess.PIPE, stderr=subprocess.PIPE, 
                                                universal_newlines=True)
                        # 实时读取输出
                        for line in iter(result.stdout.readline, ''):
                            if log_window:
                                log_window.add_log(line.rstrip())
                        for line in iter(result.stderr.readline, ''):
                            if log_window:
                                log_window.add_log("错误: " + line.rstrip())
                        result.wait()
                        if result.returncode != 0:
                            raise subprocess.CalledProcessError(result.returncode, result.args)
                    except (subprocess.CalledProcessError, FileNotFoundError):
                        try:
                            if log_window:
                                log_window.add_log("使用 sudo 执行移除命令...")
                            result = subprocess.Popen(['sudo', 'pacman', '-R', '--noconfirm'] + package_names,
                                                    stdout=subprocess.PIPE, stderr=subprocess.PIPE, 
                                                    universal_newlines=True)
                            # 实时读取输出
                            for line in iter(result.stdout.readline, ''):
                                if log_window:
                                    log_window.add_log(line.rstrip())
                            for line in iter(result.stderr.readline, ''):
                                if log_window:
                                    log_window.add_log("错误: " + line.rstrip())
                            result.wait()
                            if result.returncode != 0:
                                raise subprocess.CalledProcessError(result.returncode, result.args)
                        except (subprocess.CalledProcessError, FileNotFoundError):
                            raise PermissionError("无法移除包")
                else:
                    if log_window:
                        log_window.add_log("以 root 权限执行移除命令...")
                    result = subprocess.Popen(['pacman', '-R', '--noconfirm'] + package_names, 
                                            stdout=subprocess.PIPE, stderr=subprocess.PIPE, 
                                            universal_newlines=True)
                    # 实时读取输出
                    for line in iter(result.stdout.readline, ''):
                        if log_window:
                            log_window.add_log(line.rstrip())
                    for line in iter(result.stderr.readline, ''):
                        if log_window:
                            log_window.add_log("错误: " + line.rstrip())
                    result.wait()
                    if result.returncode != 0:
                        raise subprocess.CalledProcessError(result.returncode, result.args)
                        
            elif self.package_manager == 'zypper':
                if os.geteuid() != 0:
                    try:
                        if log_window:
                            log_window.add_log("使用 pkexec 执行移除命令...")
                        result = subprocess.Popen(['pkexec', 'zypper', 'remove', '-y'] + package_names,
                                                stdout=subprocess.PIPE, stderr=subprocess.PIPE, 
                                                universal_newlines=True)
                        # 实时读取输出
                        for line in iter(result.stdout.readline, ''):
                            if log_window:
                                log_window.add_log(line.rstrip())
                        for line in iter(result.stderr.readline, ''):
                            if log_window:
                                log_window.add_log("错误: " + line.rstrip())
                        result.wait()
                        if result.returncode != 0:
                            raise subprocess.CalledProcessError(result.returncode, result.args)
                    except (subprocess.CalledProcessError, FileNotFoundError):
                        try:
                            if log_window:
                                log_window.add_log("使用 sudo 执行移除命令...")
                            result = subprocess.Popen(['sudo', 'zypper', 'remove', '-y'] + package_names,
                                                    stdout=subprocess.PIPE, stderr=subprocess.PIPE, 
                                                    universal_newlines=True)
                            # 实时读取输出
                            for line in iter(result.stdout.readline, ''):
                                if log_window:
                                    log_window.add_log(line.rstrip())
                            for line in iter(result.stderr.readline, ''):
                                if log_window:
                                    log_window.add_log("错误: " + line.rstrip())
                            result.wait()
                            if result.returncode != 0:
                                raise subprocess.CalledProcessError(result.returncode, result.args)
                        except (subprocess.CalledProcessError, FileNotFoundError):
                            raise PermissionError("无法移除包")
                else:
                    if log_window:
                        log_window.add_log("以 root 权限执行移除命令...")
                    result = subprocess.Popen(['zypper', 'remove', '-y'] + package_names, 
                                            stdout=subprocess.PIPE, stderr=subprocess.PIPE, 
                                            universal_newlines=True)
                    # 实时读取输出
                    for line in iter(result.stdout.readline, ''):
                        if log_window:
                            log_window.add_log(line.rstrip())
                    for line in iter(result.stderr.readline, ''):
                        if log_window:
                            log_window.add_log("错误: " + line.rstrip())
                    result.wait()
                    if result.returncode != 0:
                        raise subprocess.CalledProcessError(result.returncode, result.args)
                        
        except Exception as e:
            raise RuntimeError(f"移除包失败: {str(e)}")

class InstallRecordManager:
    """安装记录管理器"""
    RECORD_FILE = ".config/kernel-management/installed-kernels.log"
    
    @classmethod
    def add_record(cls, kernel_version, packages):
        """添加安装记录"""
        try:
            os.makedirs(os.path.dirname(cls.RECORD_FILE), exist_ok=True)
            with open(cls.RECORD_FILE, 'a') as f:
                f.write(f"{kernel_version}:{','.join(packages)}\n")
        except Exception:
            pass  # 忽略记录失败
    
    @classmethod
    def remove_record(cls, kernel_version):
        """移除安装记录"""
        try:
            if not os.path.exists(cls.RECORD_FILE):
                return
            
            lines = []
            with open(cls.RECORD_FILE, 'r') as f:
                lines = f.readlines()
            
            with open(cls.RECORD_FILE, 'w') as f:
                for line in lines:
                    if not line.startswith(f"{kernel_version}:"):
                        f.write(line)
        except Exception:
            pass  # 忽略记录失败
    
    @classmethod
    def load_records(cls):
        """加载安装记录"""
        records = {}
        try:
            if os.path.exists(cls.RECORD_FILE):
                with open(cls.RECORD_FILE, 'r') as f:
                    for line in f:
                        if ':' in line:
                            kernel_version, packages = line.strip().split(':', 1)
                            records[kernel_version] = packages.split(',')
        except Exception:
            pass  # 忽略记录失败
        return records

class DefaultBootManager:
    """默认启动管理器"""
    DEFAULT_BOOT_FILE = ".config/kernel-management/default-kernel.log"
    NEXT_BOOT_FILE = ".config/kernel-management/next-boot-kernel.log"

    
    @classmethod
    def save_default_boot(cls, kernel_version):
        """保存默认启动内核记录"""
        try:
            os.makedirs(os.path.dirname(cls.DEFAULT_BOOT_FILE), exist_ok=True)
            with open(cls.DEFAULT_BOOT_FILE, 'w') as f:
                f.write(kernel_version)
        except Exception:
            pass  # 忽略记录失败
    
    @classmethod
    def save_next_boot(cls, kernel_version):
        """保存下次启动内核记录"""
        try:
            os.makedirs(os.path.dirname(cls.NEXT_BOOT_FILE), exist_ok=True)
            with open(cls.NEXT_BOOT_FILE, 'w') as f:
                f.write(kernel_version)
        except Exception:
            pass  # 忽略记录失败
    
    @classmethod
    def load_default_boot(cls):
        """加载默认启动内核记录"""
        try:
            if os.path.exists(cls.DEFAULT_BOOT_FILE):
                with open(cls.DEFAULT_BOOT_FILE, 'r') as f:
                    return f.read().strip()
        except Exception:
            pass
        return None
    
    @classmethod
    def load_next_boot(cls):
        """加载下次启动内核记录"""
        try:
            if os.path.exists(cls.NEXT_BOOT_FILE):
                with open(cls.NEXT_BOOT_FILE, 'r') as f:
                    return f.read().strip()
        except Exception:
            pass
        return None

class BootManager:
    """启动管理器"""
    def __init__(self):
        self.bootloader_type = self._detect_bootloader()
        self.grub_cfg_path = self._detect_grub_config()
        self.grub_default_path = "/etc/default/grub"
        self.grub_env_path = "/boot/grub/grubenv"
        
    def _detect_bootloader(self):
        """检测启动引导器类型"""
        # 检测systemd-boot
        if os.path.exists("/sys/firmware/efi") and (
            os.path.exists("/boot/loader/loader.conf") or 
            os.path.exists("/boot/efi/loader/loader.conf")):
            return "systemd-boot"
        
        # 检测BLS (Boot Loader Specification)
        if os.path.exists("/boot/loader/entries") or os.path.exists("/boot/efi/loader/entries"):
            return "bls"
        
        # 默认为GRUB
        return "grub"
    
    def _detect_grub_config(self):
        """检测GRUB配置文件路径"""
        possible_paths = [
            "/boot/grub/grub.cfg",
            "/boot/grub2/grub.cfg",
            "/boot/efi/EFI/fedora/grub.cfg",
            "/boot/efi/EFI/ubuntu/grub.cfg",
            "/boot/efi/EFI/arch/grub.cfg"
        ]
        
        for path in possible_paths:
            if os.path.exists(path):
                return path
                
        return "/boot/grub/grub.cfg"
    
    def get_boot_entries(self):
        """获取启动条目列表"""
        if self.bootloader_type == "systemd-boot":
            return self.get_systemd_boot_entries()
        elif self.bootloader_type == "bls":
            return self.get_bls_entries()
        else:  # GRUB
            return self.get_grub_entries()
    
    def get_grub_entries(self):
        """获取GRUB启动条目"""
        entries = []
        
        try:
            # 使用更安全的方式读取GRUB配置
            if os.geteuid() != 0:
                try:
                    result = subprocess.run(['pkexec', 'cat', self.grub_cfg_path], 
                                        capture_output=True, text=True, check=True)
                    content = result.stdout
                except (subprocess.CalledProcessError, FileNotFoundError):
                    try:
                        result = subprocess.run(['sudo', 'cat', self.grub_cfg_path], 
                                            capture_output=True, text=True, check=True)
                        content = result.stdout
                    except (subprocess.CalledProcessError, FileNotFoundError):
                        raise PermissionError("无法读取GRUB配置文件")
            else:
                with open(self.grub_cfg_path, 'r') as f:
                    content = f.read()
            
            # 改进的GRUB菜单项解析
            menuentry_pattern = re.compile(
                r'menuentry\s+(?:\'|\")(.*?)(?:\'|\")'
                r'(?:\s+--class\s+\w+(?:\s+\w+)*)?\s*\{[^}]*'
                r'(?:\n\s*linux\s+/boot/vmlinuz-(.*?)\s|\n\s*linuxefi\s+/boot/vmlinuz-(.*?)\s)',
                re.MULTILINE
            )
            
            for match in menuentry_pattern.finditer(content):
                title = match.group(1)
                version = match.group(2) or match.group(3)
                # 修改这里：使用完整的菜单项标题作为identifier，而不是内核版本号
                entries.append({
                    'title': title,
                    'version': version,
                    'identifier': title  # ！！！这里是关键修改，使用完整标题而非内核版本号
                })
                
        except Exception as e:
            print(f"解析GRUB条目失败: {e}")
            raise RuntimeError(f"无法解析GRUB启动条目: {e}")
            
        return entries
    
    def get_systemd_boot_entries(self):
        """获取systemd-boot条目"""
        entries = []
        entries_dir = "/boot/loader/entries"
        
        if not os.path.exists(entries_dir):
            entries_dir = "/boot/efi/loader/entries"
            if not os.path.exists(entries_dir):
                raise RuntimeError("找不到systemd-boot条目目录")
        
        try:
            for entry_file in os.listdir(entries_dir):
                if entry_file.endswith('.conf'):
                    with open(os.path.join(entries_dir, entry_file), 'r') as f:
                        content = f.read()
                        
                    # 解析systemd-boot条目
                    title = None
                    version = None
                    
                    for line in content.split('\n'):
                        if line.startswith('title '):
                            title = line[6:].strip()
                        elif line.startswith('options ') and 'initrd=' in line:
                            # 从options行提取版本信息
                            match = re.search(r'vmlinuz-(.*?)\s', line)
                            if match:
                                version = match.group(1)
                    
                    if title and version:
                        entries.append({
                            'title': title,
                            'version': version,
                            'identifier': os.path.splitext(entry_file)[0]
                        })
                        
        except Exception as e:
            print(f"解析BLS条目失败: {e}")
            raise RuntimeError(f"无法解析BLS启动条目: {e}")
            
        return entries
    
    def get_current_boot_entry(self):
        """获取当前启动条目"""
        if self.bootloader_type == "systemd-boot":
            return self.get_systemd_current_boot()
        elif self.bootloader_type == "bls":
            return self.get_bls_current_boot()
        else:  # GRUB
            return self.get_grub_current_boot()
    
    def get_grub_current_boot(self):
        """获取GRUB当前启动条目"""
        try:
            # 使用grubenv获取当前启动信息
            if os.geteuid() != 0:
                try:
                    result = subprocess.run(['pkexec', 'grub-editenv', self.grub_env_path, 'list'], 
                                         capture_output=True, text=True, check=True)
                    content = result.stdout
                except (subprocess.CalledProcessError, FileNotFoundError):
                    try:
                        result = subprocess.run(['sudo', 'grub-editenv', self.grub_env_path, 'list'], 
                                             capture_output=True, text=True, check=True)
                        content = result.stdout
                    except (subprocess.CalledProcessError, FileNotFoundError):
                        raise PermissionError("无法读取GRUB环境变量")
            else:
                result = subprocess.run(['grub-editenv', self.grub_env_path, 'list'], 
                                      capture_output=True, text=True, check=True)
                content = result.stdout
            
            # 解析saved_entry
            saved_entry = None
            for line in content.split('\n'):
                if line.startswith('saved_entry='):
                    saved_entry = line[12:]
                    break
                    
            if not saved_entry:
                raise RuntimeError("无法确定当前GRUB启动条目")
                
            return saved_entry
            
        except Exception as e:
            print(f"获取GRUB当前启动条目失败: {e}")
            raise RuntimeError(f"无法获取GRUB当前启动条目: {e}")
    
    def get_systemd_current_boot(self):
        """获取systemd-boot当前启动条目"""
        try:
            loader_conf = "/boot/loader/loader.conf"
            if not os.path.exists(loader_conf):
                loader_conf = "/boot/efi/loader/loader.conf"
                if not os.path.exists(loader_conf):
                    raise RuntimeError("找不到systemd-boot配置文件")
            
            if os.geteuid() != 0:
                try:
                    result = subprocess.run(['pkexec', 'cat', loader_conf], 
                                         capture_output=True, text=True, check=True)
                    content = result.stdout
                except (subprocess.CalledProcessError, FileNotFoundError):
                    try:
                        result = subprocess.run(['sudo', 'cat', loader_conf], 
                                             capture_output=True, text=True, check=True)
                        content = result.stdout
                    except (subprocess.CalledProcessError, FileNotFoundError):
                        raise PermissionError("无法读取systemd-boot配置文件")
            else:
                with open(loader_conf, 'r') as f:
                    content = f.read()
            
            # 解析default条目
            default_entry = None
            for line in content.split('\n'):
                if line.startswith('default '):
                    default_entry = line[8:].strip()
                    break
                    
            if not default_entry:
                raise RuntimeError("无法确定当前systemd-boot启动条目")
                
            return default_entry
            
        except Exception as e:
            print(f"获取systemd-boot当前启动条目失败: {e}")
            raise RuntimeError(f"无法获取systemd-boot当前启动条目: {e}")

class LogWindow:
    """日志窗口类"""
    def __init__(self, parent, title="操作日志"):
        self.window = tk.Toplevel(parent)
        self.parent = parent
        
        # 获取主窗口大小和位置信息
        parent_width = parent.winfo_width()
        parent_height = parent.winfo_height()
        parent_x = parent.winfo_x()
        parent_y = parent.winfo_y()
        
        # 设置日志窗口大小为主窗口的55%
        window_width = int(parent_width * 0.55)
        window_height = int(parent_height * 0.55)
        
        # 设置最小尺寸
        window_width = max(window_width, 400)
        window_height = max(window_height, 300)
        
        self.window.title(title)
        self.window.geometry(f"{window_width}x{window_height}")
        self.window.minsize(400, 300)
        
        # 居中显示在主窗口上
        x = parent_x + (parent_width - window_width) // 2
        y = parent_y + (parent_height - window_height) // 2
        self.window.geometry(f"{window_width}x{window_height}+{x}+{y}")
        
        # 居中显示
        self.window.transient(parent)
        self.window.grab_set()
        
        # 创建文本框和滚动条
        self.text_frame = ttk.Frame(self.window)
        self.text_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        self.log_text = scrolledtext.ScrolledText(
            self.text_frame,
            wrap=tk.WORD,
            state=tk.DISABLED
        )
        self.log_text.pack(fill=tk.BOTH, expand=True)
        
        # 创建按钮框架
        self.button_frame = ttk.Frame(self.window)
        self.button_frame.pack(fill=tk.X, padx=10, pady=(0, 10))
        
        # 清除按钮
        self.clear_button = ttk.Button(
            self.button_frame,
            text="清除日志",
            command=self.clear_log
        )
        self.clear_button.pack(side=tk.LEFT, padx=(0, 5))
        
        # 关闭按钮
        self.close_button = ttk.Button(
            self.button_frame,
            text="关闭",
            command=self.window.destroy
        )
        self.close_button.pack(side=tk.RIGHT)
        
    def add_log(self, message):
        """添加日志信息"""
        self.log_text.config(state=tk.NORMAL)
        self.log_text.insert(tk.END, message + "\n")
        self.log_text.config(state=tk.DISABLED)
        self.log_text.see(tk.END)
        self.log_text.update_idletasks()  # 确保实时更新
        
    def clear_log(self):
        """清除日志"""
        self.log_text.config(state=tk.NORMAL)
        self.log_text.delete(1.0, tk.END)
        self.log_text.config(state=tk.DISABLED)

class KernelManagementGUI:

    def __init__(self, root):
        self.root = root
        self.root.title("Linux 内核管理工具 - 作者: xiyidaiwa < a343025902@qq.com >")
        self.boot_manager = BootManager()
        self.grub_cfg_path = "/boot/grub/grub.cfg"
        self.grub_default_path = "/etc/default/grub"
        
        # 设置窗口图标
        self.setup_icon()
        
        # 根据屏幕分辨率自适应设置窗口大小
        self.setup_window_size()
        
        self.root.minsize(800, 600)
        self.root.resizable(True, True)
        
        # 设置窗口样式
        self.setup_styles()
        
        # 创建主框架
        self.main_frame = ttk.Frame(root, padding="10")
        self.main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
        
        # 配置网格权重
        root.columnconfigure(0, weight=1)
        root.rowconfigure(0, weight=1)
        self.main_frame.columnconfigure(0, weight=1)
        self.main_frame.rowconfigure(0, weight=1)
        
        # 创建主内容框架
        self.create_main_content()

        # 初始化数据
        self.root.after(100, self._delayed_refresh)  # 延迟刷新以确保界面完全初始化

    def setup_icon(self):
        """设置应用程序图标"""
        # 简化图标设置逻辑
        pass

    def setup_window_size(self):
        """
        根据屏幕分辨率自适应设置窗口大小，使用屏幕百分比
        优先在主屏幕或第一个屏幕显示
        """
        # 获取屏幕信息
        try:
            screen_width = self.root.winfo_screenwidth()
            screen_height = self.root.winfo_screenheight()
        except:
            # fallback values
            screen_width = 1920
            screen_height = 1080
        
        # 保存屏幕尺寸供后续使用
        self.screen_width = screen_width
        self.screen_height = screen_height
        
        width_ratio = 0.6
        height_ratio = 0.55
        
        window_width = int(screen_width * width_ratio)
        window_height = int(screen_height * height_ratio)
        
        # 确保窗口不会小于最小尺寸
        window_width = max(window_width, 900)
        window_height = max(window_height, 700)
        
        # 居中显示
        x = (screen_width - window_width) // 2
        y = (screen_height - window_height) // 2
        
        self.root.geometry(f"{window_width}x{window_height}+{x}+{y}")

    def setup_styles(self):
        """设置界面样式"""
        style = ttk.Style()
        style.theme_use('default')

    def create_main_content(self):
        """创建主内容区域"""
        # 创建内容框架
        content_frame = ttk.Frame(self.main_frame)
        content_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
        content_frame.columnconfigure(0, weight=1)
        content_frame.rowconfigure(3, weight=1)  # 列表框行需要权重
        
        # 标题
        title_label = ttk.Label(content_frame, text="Linux 内核管理工具", 
                               font=('Arial', 16, 'bold'))
        title_label.grid(row=0, column=0, pady=(0, 10))
        
        # 搜索框 - 放在标题下方，列表上方
        search_frame = ttk.Frame(content_frame)
        search_frame.grid(row=1, column=0, sticky=(tk.W, tk.E), pady=(5, 5))
        search_frame.columnconfigure(1, weight=1)
        
        ttk.Label(search_frame, text="搜索内核:", font=('Arial', 10)).grid(row=0, column=0, padx=(0, 5))
        self.global_search_var = tk.StringVar()
        self.global_search_var.trace('w', self.on_global_search)
        self.global_search_entry = ttk.Entry(search_frame, textvariable=self.global_search_var, font=('Arial', 10))
        self.global_search_entry.grid(row=0, column=1, sticky=(tk.W, tk.E), padx=(0, 5))
        ttk.Button(search_frame, text="清除", command=self.clear_global_search).grid(row=0, column=2, padx=(5, 0))
        
        # 安装/移除按钮框架
        button_frame = ttk.Frame(content_frame)
        button_frame.grid(row=2, column=0, sticky=(tk.W), pady=(5, 5))
        
        # 安装内核按钮
        install_btn = tk.Button(button_frame, text="安装选中内核", command=self.install_selected_kernel, fg="green")
        install_btn.grid(row=0, column=0, padx=(0, 10))
        
        # 移除内核按钮
        remove_btn = tk.Button(button_frame, text="移除选中内核", command=self.remove_selected_kernel, fg="red")
        remove_btn.grid(row=0, column=1, padx=(0, 10))
        
        # 刷新按钮
        refresh_btn = tk.Button(button_frame, text="刷新列表", command=self.refresh_all, fg="blue")
        refresh_btn.grid(row=0, column=2, padx=(0, 10))
        
        # 内核列表框
        list_frame = ttk.Frame(content_frame)
        list_frame.grid(row=3, column=0, sticky=(tk.W, tk.E, tk.N, tk.S), pady=(5, 5))
        list_frame.columnconfigure(0, weight=1)
        list_frame.rowconfigure(0, weight=1)
        
        # 创建列表框和滚动条
        self.install_listbox = tk.Listbox(list_frame, font=('Arial', 10))
        self.install_listbox.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
        
        scrollbar = ttk.Scrollbar(list_frame, orient=tk.VERTICAL, command=self.install_listbox.yview)
        scrollbar.grid(row=0, column=1, sticky=(tk.N, tk.S))
        self.install_listbox.config(yscrollcommand=scrollbar.set)
        
        # 图例框架
        legend_frame = ttk.Frame(content_frame)
        legend_frame.grid(row=4, column=0, sticky=(tk.W), pady=(5, 5))
        
        installed_indicator = tk.Label(legend_frame, text="✓ 已安装", fg="green")
        installed_indicator.grid(row=0, column=0)
        
        not_installed_indicator = tk.Label(legend_frame, text="○ 未安装", fg="gray")
        not_installed_indicator.grid(row=0, column=1)
        
        tool_installed_indicator = tk.Label(legend_frame, text="[工具安装]", fg="blue")
        tool_installed_indicator.grid(row=0, column=2, padx=(15, 0))
        
        current_indicator = tk.Label(legend_frame, text="[当前内核]", fg="purple")
        current_indicator.grid(row=0, column=3, padx=(15, 0))
        
        default_indicator = tk.Label(legend_frame, text="[默认启动]", fg="red")
        default_indicator.grid(row=0, column=4, padx=(15, 0))
        
        next_indicator = tk.Label(legend_frame, text="[下次启动]", fg="orange")
        next_indicator.grid(row=0, column=5, padx=(15, 0))
        
        # 添加设置默认启动内核按钮
        set_default_frame = ttk.Frame(content_frame)
        set_default_frame.grid(row=5, column=0, sticky=(tk.E), pady=(5, 5))
        
        # 临时设置默认内核按钮
        set_temp_default_btn = tk.Button(set_default_frame, text="设为下次启动内核", command=lambda: self.set_default_kernel(permanent=False), fg="orange")
        set_temp_default_btn.grid(row=0, column=0, padx=(0, 10))
        
        # 永久设置默认内核按钮
        set_perm_default_btn = tk.Button(set_default_frame, text="⚠️设为默认启动内核⚠️", command=lambda: self.set_default_kernel(permanent=True), fg="red")
        set_perm_default_btn.grid(row=0, column=1, padx=(0, 10))
        
        # 使用推荐方式设置默认内核按钮
        set_recommended_default_btn = tk.Button(set_default_frame, text="使用推荐方式设为默认内核", command=lambda: self.set_default_kernel_with_recommended_method(permanent=True), fg="blue")
        set_recommended_default_btn.grid(row=0, column=2, padx=(0, 10))
        
        # 添加全局说明文本
        info_text = """
⚠️ 警告：内核管理操作具有高风险-使用本软件表示您已完全了解并同意所有风险。 ⚠️
- 在使用本工具前，请务必了解以下事项：
- 1. 安装或移除内核可能影响系统稳定性
- 2. 操作前请确保已备份重要数据
- 3. 建议在有经验的用户指导下操作
- 4. 软件作者对使用本软件产生的任何损失不承担任何责任
- 请务必阅读以上注意事项，并请务必保证您完全了解内核管理操作所带来的影响再继续使用该工具！
        """
        self.global_info_label = ttk.Label(content_frame, text=info_text, justify=tk.LEFT)
        self.global_info_label.grid(row=6, column=0, sticky=(tk.W, tk.E), pady=(5, 5))
        
        # 添加状态标签
        self.install_status_var = tk.StringVar()
        self.install_status_var.set("就绪")
        status_label = ttk.Label(content_frame, textvariable=self.install_status_var, relief=tk.SUNKEN, anchor=tk.W)
        status_label.grid(row=7, column=0, sticky=(tk.W, tk.E), pady=(5, 0))
        
        # 底部作者信息
        version = KM_VERSION
        self.author_frame = ttk.Frame(content_frame)
        self.author_frame.grid(row=8, column=0, sticky=(tk.W, tk.E), pady=(5, 0))
        self.author_frame.columnconfigure(0, weight=1)
        
        self.author_label = ttk.Label(self.author_frame, 
                                    text=f"作者: xiyidaiwa < a343025902@qq.com >\n" \
                                    f"网址: https://gitee.com/gys1987/simple-management-of-the-kernel\n" \
                                    f"版本: {version}",
                                    relief=tk.SUNKEN, anchor=tk.CENTER, justify=tk.CENTER)
        self.author_label.grid(row=0, column=0, sticky=(tk.W, tk.E))

    def _delayed_refresh(self):
        """延迟刷新以确保界面完全初始化"""
        try:
            self.refresh_all()
        except Exception as e:
            self.install_status_var.set(f"初始化失败: {str(e)}")
            self.root.update_idletasks()

    def get_all_available_kernels(self):
        """获取所有可用的内核包"""
        try:
            # 使用包管理器检测
            package_manager = PackageManager()
            
            if package_manager.package_manager == 'apt':
                result = subprocess.run(['apt-cache', 'search', '^linux-image'], 
                                    capture_output=True, text=True, check=True)
                kernels = []
                for line in result.stdout.split('\n'):
                    if line.strip():
                        kernel_name = line.split()[0]
                        # 过滤掉包含'extra'和'dbg'的内核
                        if (kernel_name.startswith('linux-image-') and 
                            'extra' not in kernel_name and 
                            'dbg' not in kernel_name):
                            kernels.append(kernel_name)
                return kernels
            elif package_manager.package_manager in ['dnf', 'yum']:
                cmd = 'dnf' if package_manager.package_manager == 'dnf' else 'yum'
                result = subprocess.run([cmd, 'search', 'kernel'], 
                                    capture_output=True, text=True, check=True)
                kernels = []
                for line in result.stdout.split('\n'):
                    if line.strip() and not line.startswith('======='):
                        # 解析DNF/YUM输出格式
                        parts = line.split()
                        if parts and (parts[0].startswith('kernel-') or 'kernel' in parts[0]):
                            kernels.append(parts[0])
                return kernels
            elif package_manager.package_manager == 'pacman':
                result = subprocess.run(['pacman', '-Ss', 'linux'], 
                                      capture_output=True, text=True, check=True)
                kernels = []
                for line in result.stdout.split('\n'):
                    if line.strip() and line.startswith('core/linux'):
                        kernel_name = line.split()[0].split('/')[1]
                        kernels.append(kernel_name)
                return kernels
            elif package_manager.package_manager == 'zypper':
                result = subprocess.run(['zypper', 'search', '-i', 'kernel*'], 
                                      capture_output=True, text=True, check=True)
                kernels = []
                for line in result.stdout.split('\n'):
                    if line.strip() and (line.startswith('i') or '| i ' in line):
                        kernel_name = line.split('|')[2].strip()
                        if kernel_name.startswith('kernel'):
                            kernels.append(kernel_name)
                return kernels
            else:
                self.show_message("错误", f"不支持的包管理器: {package_manager.package_manager}", 'error')
                return []
        except subprocess.CalledProcessError:
            self.show_message("错误", "无法获取可用内核列表", 'error')
            return []
        
    def get_installed_kernels(self):
        """列出所有已安装的内核"""
        try:
            # 使用包管理器检测
            package_manager = PackageManager()
            
            if package_manager.package_manager == 'apt':
                result = subprocess.run(['dpkg', '--list', 'linux-image-*'], 
                                      capture_output=True, text=True, check=True)
                kernels = []
                for line in result.stdout.split('\n'):
                    if line.startswith('ii'):
                        kernel_name = line.split()[1]
                        if kernel_name.startswith('linux-image-') and 'extra' not in kernel_name:
                            kernels.append(kernel_name)
                return kernels
            elif package_manager.package_manager in ['dnf', 'yum']:
                cmd = 'dnf' if package_manager.package_manager == 'dnf' else 'yum'
                result = subprocess.run([cmd, 'list', 'installed', 'kernel*'], 
                                      capture_output=True, text=True, check=True)
                kernels = []
                for line in result.stdout.split('\n')[1:]:  # 跳过标题行
                    if line.strip():
                        parts = line.split()
                        if parts and parts[0].startswith('kernel'):
                            # 从包名中提取版本信息
                            kernel_name = parts[0]
                            kernels.append(kernel_name)
                return kernels
            elif package_manager.package_manager == 'pacman':
                result = subprocess.run(['pacman', '-Qs', 'linux'], 
                                      capture_output=True, text=True, check=True)
                kernels = []
                for line in result.stdout.split('\n'):
                    if line.strip() and line.startswith('local/linux'):
                        kernel_name = line.split()[0].split('/')[1]
                        kernels.append(kernel_name)
                return kernels
            elif package_manager.package_manager == 'zypper':
                result = subprocess.run(['zypper', 'search', '-i', 'kernel*'], 
                                      capture_output=True, text=True, check=True)
                kernels = []
                for line in result.stdout.split('\n'):
                    if line.strip() and (line.startswith('i') or '| i ' in line):
                        kernel_name = line.split('|')[1].strip()
                        if kernel_name.startswith('kernel-'):
                            kernels.append(kernel_name)
                return kernels
            else:
                self.show_message("错误", f"不支持的包管理器: {package_manager.package_manager}", 'error')
                return []
        except subprocess.CalledProcessError:
            self.show_message("错误", "无法获取已安装内核列表", 'error')
            return []
    
    def get_current_kernel(self):
        """获取当前正在使用的内核"""
        try:
            result = subprocess.run(['uname', '-r'], 
                                  capture_output=True, text=True, check=True)
            return result.stdout.strip()
        except subprocess.CalledProcessError:
            return None

    def refresh_install(self):
        """刷新可用内核列表，在其中标注已安装的内核"""
        try:
            self.install_status_var.set("正在获取可用内核...")
            self.root.update_idletasks()
            
            self.install_listbox.delete(0, tk.END)
            available_kernels = self.get_all_available_kernels()
            installed_kernels = self.get_installed_kernels()
            current_kernel = self.get_current_kernel()
            
            # 提取已安装内核的版本号用于比较
            installed_versions = {}
            for kernel in installed_kernels:
                # 根据不同包管理器提取版本号
                if kernel.startswith('linux-image-'):
                    version = kernel.replace('linux-image-', '')
                elif kernel.startswith('kernel-'):
                    version = kernel.replace('kernel-', '')
                else:
                    version = kernel.replace('linux-', '')
                installed_versions[version] = kernel  # 保存完整内核名和版本的映射
            
            # 加载安装记录
            install_records = InstallRecordManager.load_records()
            
            # 加载默认启动和下次启动内核记录
            default_boot_kernel = DefaultBootManager.load_default_boot()
            next_boot_kernel = DefaultBootManager.load_next_boot()
            
            # 分别存储已安装和未安装的内核
            installed_kernels_list = []
            available_kernels_list = []
            
            # 处理已安装的内核
            for kernel in installed_kernels:
                # 根据不同包管理器提取版本号
                if kernel.startswith('linux-image-'):
                    version = kernel.replace('linux-image-', '')
                elif kernel.startswith('kernel-'):
                    version = kernel.replace('kernel-', '')
                else:
                    version = kernel.replace('linux-', '')
                
                # 检查各种标记
                is_current = False
                if current_kernel and (
                    current_kernel == version or 
                    version in current_kernel or 
                    current_kernel in version):
                    is_current = True
                
                # 检查是否通过本工具安装
                is_tool_installed = version in install_records
                
                # 检查是否为默认启动内核 (使用更宽松的匹配)
                is_default = False
                if default_boot_kernel and (
                    default_boot_kernel == version or 
                    version in default_boot_kernel or 
                    default_boot_kernel in version):
                    is_default = True
                
                # 检查是否为下次启动内核 (使用更宽松的匹配)
                is_next = False
                if next_boot_kernel and (
                    next_boot_kernel == version or 
                    version in next_boot_kernel or 
                    next_boot_kernel in version):
                    is_next = True
                
                # 构建显示文本 - 按照指定顺序显示标记
                display_text = f"✓ {kernel}"
                tags = []
                
                if is_current:
                    tags.append("当前内核")
                
                if is_next:
                    tags.append("下次启动")
                
                if is_default:
                    tags.append("默认启动")
                
                if is_tool_installed:
                    tags.append("工具安装")
                
                # 按照指定顺序添加标记
                if tags:
                    display_text += " [" + "][".join(tags) + "]"
                
                installed_kernels_list.append((display_text, "green"))
            
            # 处理未安装的内核
            for kernel in available_kernels:
                # 检查是否已安装（避免重复显示）
                is_installed = False
                if kernel.startswith('linux-image-'):
                    version = kernel.replace('linux-image-', '')
                elif kernel.startswith('kernel-'):
                    version = kernel.replace('kernel-', '')
                else:
                    version = kernel.replace('linux-', '')
                
                if version in installed_versions:
                    is_installed = True
                
                if not is_installed:
                    display_text = f"○ {kernel}"
                    available_kernels_list.append((display_text, "gray"))
            
            # 保存所有项目以供搜索使用
            self._all_install_items = installed_kernels_list + available_kernels_list
            
            # 先显示已安装的内核
            for display_text, color in installed_kernels_list:
                self.install_listbox.insert(tk.END, display_text)
                # 设置已安装项的样式
                self.install_listbox.itemconfig(tk.END, fg=color)
                
            # 再显示未安装的内核
            for display_text, color in available_kernels_list:
                self.install_listbox.insert(tk.END, display_text)
                # 设置未安装项的样式
                self.install_listbox.itemconfig(tk.END, fg=color)
            
            # 如果有搜索内容，应用搜索过滤
            search_term = self.global_search_var.get().lower()
            if search_term:
                self.on_global_search()
            
            # 数据刷新完成后，更新状态栏文本
            self.install_status_var.set(f"就绪 (可用内核: {len(available_kernels)}, 已安装内核: {len(installed_kernels)})")
            
        except Exception as e:
            self.install_status_var.set(f"刷新失败: {str(e)}")
            import traceback
            traceback.print_exc()
        finally:
            # 确保状态栏更新立即显示
            try:
                self.root.update_idletasks()
            except:
                pass

    def on_global_search(self, *args):
        """处理全局搜索输入变化"""
        search_term = self.global_search_var.get().lower()
        
        if hasattr(self, '_all_install_items'):
            self.install_listbox.delete(0, tk.END)
            for item, color in self._all_install_items:
                if search_term in item.lower():
                    self.install_listbox.insert(tk.END, item)
                    self.install_listbox.itemconfig(tk.END, fg=color)

    def clear_global_search(self):
        """清除全局搜索框"""
        self.global_search_var.set("")
        
        if hasattr(self, '_all_install_items'):
            self.install_listbox.delete(0, tk.END)
            for item, color in self._all_install_items:
                self.install_listbox.insert(tk.END, item)
                self.install_listbox.itemconfig(tk.END, fg=color)

    def install_selected_kernel(self):
        """安装选中的内核"""
        selection = self.install_listbox.curselection()
        if not selection:
            self.show_message("提示", "请先选择一个内核", 'warning')
            return
            
        item = self.install_listbox.get(selection[0])
        
        # 检查是否已安装
        if item.startswith("✓"):
            self.show_message("提示", "该内核已安装，无法重复安装", 'warning')
            return
            
        # 提取内核名称（去除标记符号）
        kernel_name = item.replace("✓ ", "").replace("○ ", "").split(" ")[0]
        
        # 确认安装
        if not messagebox.askyesno("确认安装", f"确定要安装内核 {kernel_name} 吗？"):
            return
            
        # 创建日志窗口
        log_window = LogWindow(self.root, f"安装内核 {kernel_name} 的日志")
        log_window.add_log(f"开始安装内核: {kernel_name}")
        
        self.install_status_var.set(f"正在安装 {kernel_name}...")
        self.root.update_idletasks()
        
        try:
            # 使用包管理器安装
            package_manager = PackageManager()
            log_window.add_log(f"检测到的包管理器: {package_manager.package_manager}")
            
            # 获取相关的包名
            base_version = kernel_name.replace('linux-image-', '').replace('kernel-', '').replace('linux-', '')
            package_names = package_manager.get_package_names(base_version, 'install')
            log_window.add_log(f"将要安装的包: {', '.join(package_names)}")
            
            # 安装包
            installed_packages = package_manager.install_packages(package_names, log_window)
                
            # 记录安装信息
            InstallRecordManager.add_record(base_version, installed_packages)
            log_window.add_log(f"内核 {kernel_name} 安装完成，已记录安装信息")
            self.show_message("成功", f"内核 {kernel_name} 安装完成", 'info')
            self.refresh_install()
            
        except Exception as e:
            log_window.add_log(f"安装内核失败: {str(e)}")
            self.show_message("错误", f"安装内核失败: {str(e)}", 'error')
            self.install_status_var.set("安装失败")
        else:
            self.install_status_var.set("安装完成")

    def remove_selected_kernel(self):
        """移除选中的内核"""
        selection = self.install_listbox.curselection()
        if not selection:
            self.show_message("提示", "请先选择一个内核", 'warning')
            return
            
        item = self.install_listbox.get(selection[0])
        # 检查是否已安装
        if not item.startswith("✓"):
            self.show_message("提示", "只能移除已安装的内核", 'warning')
            return
            
        # 检查是否有保护标记
        if "当前内核" in item or "下次启动" in item or "默认启动" in item:
            self.show_message("提示", "无法移除当前内核、下次启动内核或默认启动内核", 'warning')
            return
            
        # 提取内核名称（去除标记符号）
        kernel_name = item.replace("✓ ", "").split(" ")[0]
        
        # 双重保障：检查是否为当前正在运行的内核
        current_kernel = self.get_current_kernel()
        # 根据不同包管理器提取版本号进行比较
        if kernel_name.startswith('linux-image-'):
            kernel_version = kernel_name.replace('linux-image-', '')
        elif kernel_name.startswith('kernel-'):
            kernel_version = kernel_name.replace('kernel-', '')
        else:
            kernel_version = kernel_name.replace('linux-', '')
            
        # 检查是否与当前运行内核匹配（更宽松的匹配）
        if current_kernel and (
            current_kernel == kernel_version or 
            kernel_version in current_kernel or 
            current_kernel in kernel_version):
            self.show_message("提示", "无法移除当前正在运行的内核", 'warning')
            return
        
        # 确认移除
        if not messagebox.askyesno("确认移除", f"确定要移除内核 {kernel_name} 吗？"):
            return
            
        # 创建日志窗口
        log_window = LogWindow(self.root, f"移除内核 {kernel_name} 的日志")
        log_window.add_log(f"开始移除内核: {kernel_name}")
        
        self.install_status_var.set(f"正在移除 {kernel_name}...")
        self.root.update_idletasks()
        
        try:
            # 使用包管理器移除
            package_manager = PackageManager()
            log_window.add_log(f"检测到的包管理器: {package_manager.package_manager}")
            
            # 获取相关的包名
            base_version = kernel_name.replace('linux-image-', '').replace('kernel-', '').replace('linux-', '')
            package_names = package_manager.get_package_names(base_version, 'remove')
            log_window.add_log(f"将要移除的包: {package_names}")
            
            # 移除包
            package_manager.remove_packages(package_names, log_window)
            
            # 移除安装记录
            InstallRecordManager.remove_record(base_version)
            log_window.add_log(f"内核 {package_names} 移除完成，已清除安装记录")
            self.show_message("成功", f"内核 {package_names} 移除完成", 'info')
            self.refresh_install()
            
        except Exception as e:
            log_window.add_log(f"移除内核失败: {str(e)}")
            self.show_message("错误", f"移除内核失败: {str(e)}", 'error')
            self.install_status_var.set("移除失败")
        else:
            self.install_status_var.set("移除完成")

    def set_default_kernel(self, permanent=True):
        """设置默认启动内核"""
        selection = self.install_listbox.curselection()
        if not selection:
            self.show_message("提示", "请先选择一个内核", 'warning')
            return
            
        item = self.install_listbox.get(selection[0])
        # 提取内核名称（去除标记符号）
        kernel_name = item.replace("✓ ", "").replace("○ ", "").split(" ")[0]
        
        # 确认设置
        action_type = "永久" if permanent else "临时"
        if not messagebox.askyesno("确认设置", f"确定要将 {kernel_name} 设置为{action_type}默认启动内核吗？"):
            return
            
        # 创建日志窗口
        log_window = LogWindow(self.root, f"设置{action_type}默认内核 {kernel_name} 的日志")
        log_window.add_log(f"开始设置{action_type}默认启动内核: {kernel_name}")
        
        self.install_status_var.set(f"正在设置 {kernel_name} 为{action_type}默认启动内核...")
        self.root.update_idletasks()
        
        try:
            # 获取启动条目
            log_window.add_log("获取启动条目列表...")
            boot_entries = self.boot_manager.get_boot_entries()
            log_window.add_log(f"找到 {len(boot_entries)} 个启动条目")
            
            target_entry = None
            
            # 根据不同包管理器提取版本号
            if kernel_name.startswith('linux-image-'):
                kernel_version = kernel_name.replace('linux-image-', '')
            elif kernel_name.startswith('kernel-'):
                kernel_version = kernel_name.replace('kernel-', '')
            else:
                kernel_version = kernel_name.replace('linux-', '')
            
            # 查找匹配的启动条目
            for entry in boot_entries:
                log_window.add_log(f"检查条目: {entry['title']} (版本: {entry['version']})")
                if entry['version'] and entry['version'] in kernel_name:
                    target_entry = entry
                    log_window.add_log(f"找到匹配条目: {entry['title']}")
                    break
            
            if not target_entry:
                raise RuntimeError("找不到匹配的启动条目")
            
            # 设置默认启动条目
            entry_id = target_entry['identifier']
            log_window.add_log(f"使用条目ID设置默认启动项: {entry_id}")
            
            if permanent:
                # 永久设置 - 修改配置文件
                if os.geteuid() != 0:
                    try:
                        result = subprocess.run(['pkexec', 'cat', self.grub_default_path], 
                                            capture_output=True, text=True, check=True)
                        content = result.stdout.splitlines(keepends=True)
                    except (subprocess.CalledProcessError, FileNotFoundError):
                        try:
                            result = subprocess.run(['sudo', 'cat', self.grub_default_path],
                                                  capture_output=True, text=True, check=True)
                            content = result.stdout.splitlines(keepends=True)
                        except (subprocess.CalledProcessError, FileNotFoundError):
                            raise PermissionError("无法读取GRUB默认配置")
                else:
                    with open(self.grub_default_path, 'r') as f:
                        content = f.readlines()
                
                # 清理entry_id，确保它是有效的标识符
                cleaned_entry_id = self._clean_grub_entry_id(entry_id)
                
                # 更新GRUB_DEFAULT
                new_content = []
                updated = False
                for line in content:
                    if line.startswith('GRUB_DEFAULT='):
                        new_content.append(f'GRUB_DEFAULT="{cleaned_entry_id}"\n')
                        updated = True
                    else:
                        new_content.append(line)
                
                if not updated:
                    new_content.append(f'GRUB_DEFAULT="{cleaned_entry_id}"\n')
                
                # 使用临时文件安全地写入
                with tempfile.NamedTemporaryFile(mode='w', delete=False) as tmp_file:
                    tmp_file.writelines(new_content)
                    tmp_path = tmp_file.name
                
                try:
                    if os.geteuid() != 0:
                        try:
                            subprocess.run(['pkexec', 'cp', tmp_path, self.grub_default_path], 
                                        check=True)
                        except (subprocess.CalledProcessError, FileNotFoundError):
                            try:
                                subprocess.run(['sudo', 'cp', tmp_path, self.grub_default_path], 
                                            check=True)
                            except (subprocess.CalledProcessError, FileNotFoundError):
                                raise PermissionError("无法更新GRUB默认配置")
                    else:
                        shutil.copy(tmp_path, self.grub_default_path)
                finally:
                    os.unlink(tmp_path)
                
                # 更新GRUB配置
                self.update_grub_config()
                
                # 验证设置是否成功
                try:
                    if os.geteuid() != 0:
                        try:
                            result = subprocess.run(['pkexec', 'grep', '^GRUB_DEFAULT=', self.grub_default_path], 
                                                capture_output=True, text=True, check=True)
                        except (subprocess.CalledProcessError, FileNotFoundError):
                            try:
                                result = subprocess.run(['sudo', 'grep', '^GRUB_DEFAULT=', self.grub_default_path], 
                                                    capture_output=True, text=True, check=True)
                            except (subprocess.CalledProcessError, FileNotFoundError):
                                raise PermissionError("无法验证GRUB默认配置")
                    else:
                        result = subprocess.run(['grep', '^GRUB_DEFAULT=', self.grub_default_path], 
                                            capture_output=True, text=True, check=True)
                    
                    if f'GRUB_DEFAULT="{cleaned_entry_id}"' not in result.stdout:
                        raise RuntimeError("验证永久GRUB默认启动条目设置失败")
                except subprocess.CalledProcessError:
                    raise RuntimeError("验证GRUB默认启动条目设置失败")
                
                # 记录到本地文件
                DefaultBootManager.save_default_boot(kernel_version)
                log_window.add_log("已记录为默认启动内核")
            else:
                # 临时设置 - 使用grub-reboot
                commands_to_try = [
                    ['grub-reboot', entry_id],
                    ['/usr/sbin/grub-reboot', entry_id]
                ]
                
                success = False
                if os.geteuid() != 0:
                    for cmd in commands_to_try:
                        try:
                            subprocess.run(['pkexec'] + cmd, check=True)
                            success = True
                            break
                        except (subprocess.CalledProcessError, FileNotFoundError):
                            try:
                                subprocess.run(['sudo'] + cmd, check=True)
                                success = True
                                break
                            except (subprocess.CalledProcessError, FileNotFoundError):
                                continue
                else:
                    for cmd in commands_to_try:
                        try:
                            subprocess.run(cmd, check=True)
                            success = True
                            break
                        except (subprocess.CalledProcessError, FileNotFoundError):
                            continue
                
                if not success:
                    raise RuntimeError("无法设置临时GRUB默认启动条目")
                
                # 记录到本地文件
                DefaultBootManager.save_next_boot(kernel_version)
                log_window.add_log("已记录为下次启动内核")
            
            log_window.add_log(f"{action_type}默认启动条目设置完成")
            self.show_message("成功", f"已将 {kernel_name} 设置为{action_type}默认启动内核", 'info')
            self.refresh_install()  # 刷新显示以更新标记
            
        except Exception as e:
            log_window.add_log(f"设置{action_type}默认启动内核失败: {str(e)}")
            self.show_message("错误", f"设置{action_type}默认启动内核失败: {str(e)}", 'error')
            self.install_status_var.set("设置失败")
            self.root.update_idletasks()
        else:
            self.install_status_var.set("设置完成")
            self.root.update_idletasks()  # 确保状态更新立即显示

    def set_default_kernel_with_recommended_method(self, permanent=True):
        """
        使用GRUB推荐方式设置默认启动内核
        根据GRUB版本使用不同的格式:
        - GRUB < 2.00: "Advanced options for Ubuntu>Ubuntu, with Linux X.X.X-generic"
        - GRUB >= 2.00: "gnulinux-advanced-UUID>gnulinux-X.X.X-generic-advanced-UUID"
        """
        selection = self.install_listbox.curselection()
        if not selection:
            self.show_message("提示", "请先选择一个内核", 'warning')
            return
            
        item = self.install_listbox.get(selection[0])
        # 提取内核名称（去除标记符号）
        kernel_name = item.replace("✓ ", "").replace("○ ", "").split(" ")[0]
        
        # 根据不同包管理器提取版本号
        if kernel_name.startswith('linux-image-'):
            kernel_version = kernel_name.replace('linux-image-', '')
        elif kernel_name.startswith('kernel-'):
            kernel_version = kernel_name.replace('kernel-', '')
        else:
            kernel_version = kernel_name.replace('linux-', '')
        
        # 确认设置
        action_type = "永久" if permanent else "临时"
        if not messagebox.askyesno("确认设置", f"确定要将 {kernel_name} 设置为{action_type}默认启动内核吗？\n将使用GRUB推荐方式设置。"):
            return
            
        # 创建日志窗口
        log_window = LogWindow(self.root, f"设置{action_type}默认内核 {kernel_name} 的日志")
        log_window.add_log(f"开始设置{action_type}默认启动内核: {kernel_name}")
        log_window.add_log(f"内核版本: {kernel_version}")
        
        self.install_status_var.set(f"正在设置 {kernel_name} 为{action_type}默认启动内核...")
        self.root.update_idletasks()
        
        try:
            # 获取GRUB版本
            grub_version = self.get_grub_version()
            log_window.add_log(f"检测到GRUB版本: {grub_version}")
            
            # 查找目标内核条目
            target_entry = self.find_grub_entry_for_kernel(kernel_version)
            if not target_entry:
                raise RuntimeError(f"在GRUB菜单中找不到内核 {kernel_version} 的条目")
            
            log_window.add_log(f"找到目标条目: {target_entry['title']} (版本: {target_entry['version']})")
            
            # 根据GRUB版本选择合适的设置方式
            if grub_version and self.is_grub_200_or_later(grub_version):
                # GRUB 2.00及以上版本使用唯一标识符方式
                menu_path = self.construct_grub_200_plus_menu_path(kernel_version)
                log_window.add_log(f"使用GRUB 2.00+推荐方式设置默认启动项: {menu_path}")
            else:
                # GRUB 2.00以下版本使用菜单路径方式
                menu_path = f"Advanced options for Ubuntu>{target_entry['title']}"
                log_window.add_log(f"使用GRUB <2.00推荐方式设置默认启动项: {menu_path}")
            
            # 设置默认启动项
            if permanent:
                self._update_grub_default_config(f'GRUB_DEFAULT="{menu_path}"')
                log_window.add_log("已永久设置GRUB默认启动项")
                # 记录到本地文件
                DefaultBootManager.save_default_boot(kernel_version)
                log_window.add_log("已记录为默认启动内核")
            else:
                self._set_next_boot_entry(menu_path)
                log_window.add_log("已设置下次启动项")
                # 记录到本地文件
                DefaultBootManager.save_next_boot(kernel_version)
                log_window.add_log("已记录为下次启动内核")
            
            log_window.add_log(f"{action_type}默认启动条目设置完成")
            log_window.add_log(f"已将 {kernel_name} 设置为{action_type}默认启动内核（使用GRUB推荐方式）")
            self.show_message("成功", f"已将 {kernel_name} 设置为{action_type}默认启动内核", 'info')
            self.refresh_install()  # 刷新显示以更新标记
            
        except Exception as e:
            log_window.add_log(f"设置{action_type}默认启动内核失败: {str(e)}")
            self.show_message("错误", f"设置{action_type}默认启动内核失败: {str(e)}", 'error')
            self.install_status_var.set("设置失败")
            self.root.update_idletasks()
        else:
            self.install_status_var.set("设置完成")
            self.root.update_idletasks()  # 确保状态更新立即显示

    def get_grub_version(self):
        """获取GRUB版本"""
        try:
            result = subprocess.run(['grub-install', '--version'], 
                                  capture_output=True, text=True, check=True)
            version_line = result.stdout.strip()
            # 提取版本号 (格式: "grub-install (GRUB) 2.06")
            import re
            match = re.search(r'GRUB\)\s+([\d.]+)', version_line)
            if match:
                return match.group(1)
        except (subprocess.CalledProcessError, FileNotFoundError):
            pass
        return None

    def is_grub_200_or_later(self, version_str):
        """判断GRUB版本是否为2.00或更高"""
        try:
            from packaging import version
            return version.parse(version_str) >= version.parse("2.00")
        except:
            # 简单的字符串比较作为备选方案
            version_parts = version_str.split('.')
            if int(version_parts[0]) > 2:
                return True
            elif int(version_parts[0]) == 2:
                if len(version_parts) > 1 and int(version_parts[1]) >= 0:
                    return True
            return False

    def find_grub_entry_for_kernel(self, target_kernel_version):
        """查找GRUB中对应内核的条目"""
        try:
            # 获取GRUB条目
            entries = self.boot_manager.get_grub_entries()
            if not entries:
                return None
            
            # 查找目标内核条目（优先选择非恢复模式的条目）
            target_entry = None
            for entry in entries:
                if (entry['version'] and 
                    (target_kernel_version == entry['version'] or 
                     target_kernel_version in entry['version'] or 
                     entry['version'] in target_kernel_version) and
                    'recovery' not in entry['title'].lower() and 
                    '恢复' not in entry['title']):
                    target_entry = entry
                    break
            
            # 如果没找到非恢复模式条目，则查找任何匹配的条目
            if not target_entry:
                for entry in entries:
                    if (entry['version'] and 
                        (target_kernel_version == entry['version'] or 
                         target_kernel_version in entry['version'] or 
                         entry['version'] in target_kernel_version)):
                        target_entry = entry
                        break
            
            return target_entry
        except Exception as e:
            print(f"查找GRUB条目失败: {e}")
            return None

    def construct_grub_200_plus_menu_path(self, kernel_version):
        """
        通过匹配而非构造来获取GRUB 2.00+的菜单路径
        """
        try:
            # 首先尝试获取实际的GRUB条目
            entries = self.boot_manager.get_grub_entries()
            
            # 查找匹配的目标内核条目
            target_entry = None
            for entry in entries:
                if (entry['version'] and 
                    (kernel_version == entry['version'] or 
                    kernel_version in entry['version'] or 
                    entry['version'] in kernel_version) and
                    'recovery' not in entry['title'].lower()):
                    target_entry = entry
                    break
            
            # 如果找到了匹配的条目，直接使用其identifier
            if target_entry and 'identifier' in target_entry:
                # 对于GRUB 2.00+，我们可能需要构建完整的菜单路径
                # 检查identifier是否已经是完整路径格式
                if '>' in target_entry['identifier']:
                    return target_entry['identifier']
                else:
                    # 如果是单级ID，尝试构建完整路径
                    root_uuid = self.get_root_uuid()
                    if root_uuid:
                        advanced_menu_id = f"gnulinux-advanced-{root_uuid}"
                        return f"{advanced_menu_id}>{target_entry['identifier']}"
                    else:
                        # 回退到使用标题匹配
                        return f"Advanced options for Ubuntu>{target_entry['title']}"
            
            # 如果没有找到匹配条目，回退到原来的构造方法
            root_uuid = self.get_root_uuid()
            if not root_uuid:
                root_uuid = "4468d89a-bf3f-41e7-b244-ff47e9c3ee02"
            
            advanced_menu_id = f"gnulinux-advanced-{root_uuid}"
            kernel_entry_id = f"gnulinux-{kernel_version}-advanced-{root_uuid}"
            
            return f"{advanced_menu_id}>{kernel_entry_id}"
        except Exception as e:
            return f"Advanced options for Ubuntu>Ubuntu, with Linux {kernel_version}"

    def get_root_uuid(self):
        """获取根分区UUID"""
        try:
            # 尝试多种方式获取根分区UUID
            commands = [
                ['lsblk', '-f', '-o', 'UUID,MOUNTPOINT'],
                ['sudo', 'lsblk', '-f', '-o', 'UUID,MOUNTPOINT'],
                ['pkexec', 'lsblk', '-f', '-o', 'UUID,MOUNTPOINT']
            ]
            
            for cmd in commands:
                try:
                    result = subprocess.run(cmd, capture_output=True, text=True, check=True)
                    lines = result.stdout.strip().split('\n')
                    for line in lines[1:]:  # 跳过标题行
                        parts = line.split()
                        if len(parts) >= 2 and '/' in parts[-1] and parts[-1].strip() == '/':
                            return parts[0]  # 返回根分区UUID
                except (subprocess.CalledProcessError, FileNotFoundError):
                    continue
                    
            # 如果上面的方法失败，尝试使用blkid
            try:
                result = subprocess.run(['blkid'], capture_output=True, text=True, check=True)
                # 查找包含"/"的行（根分区）
                import re
                for line in result.stdout.split('\n'):
                    if 'UUID=' in line and '/dev/' in line:
                        uuid_match = re.search(r'UUID="([^"]+)"', line)
                        if uuid_match and '/dev/' in line:
                            # 进一步确认是否为根分区
                            if 'TYPE="ext"' in line or 'TYPE="btrfs"' in line or 'TYPE="xfs"' in line:
                                return uuid_match.group(1)
            except (subprocess.CalledProcessError, FileNotFoundError):
                pass
                
        except Exception as e:
            print(f"获取根分区UUID失败: {e}")
        
        return None

    def _update_grub_default_config(self, new_default_line):
        """更新GRUB默认配置文件"""
        try:
            # 读取当前配置
            if os.geteuid() != 0:
                try:
                    result = subprocess.run(['pkexec', 'cat', self.grub_default_path], 
                                          capture_output=True, text=True, check=True)
                    content = result.stdout.splitlines(keepends=True)
                except (subprocess.CalledProcessError, FileNotFoundError):
                    try:
                        result = subprocess.run(['sudo', 'cat', self.grub_default_path],
                                              capture_output=True, text=True, check=True)
                        content = result.stdout.splitlines(keepends=True)
                    except (subprocess.CalledProcessError, FileNotFoundError):
                        raise PermissionError("无法读取GRUB默认配置")
            else:
                with open(self.grub_default_path, 'r') as f:
                    content = f.readlines()
            
            # 更新GRUB_DEFAULT行
            new_content = []
            updated = False
            for line in content:
                if line.startswith('GRUB_DEFAULT='):
                    new_content.append(new_default_line + '\n')
                    updated = True
                else:
                    new_content.append(line)
            
            if not updated:
                new_content.append(new_default_line + '\n')
            
            # 使用临时文件安全地写入
            with tempfile.NamedTemporaryFile(mode='w', delete=False) as tmp_file:
                tmp_file.writelines(new_content)
                tmp_path = tmp_file.name
            
            try:
                if os.geteuid() != 0:
                    try:
                        subprocess.run(['pkexec', 'cp', tmp_path, self.grub_default_path], 
                                     check=True)
                    except (subprocess.CalledProcessError, FileNotFoundError):
                        try:
                            subprocess.run(['sudo', 'cp', tmp_path, self.grub_default_path], 
                                         check=True)
                        except (subprocess.CalledProcessError, FileNotFoundError):
                            raise PermissionError("无法更新GRUB默认配置")
                else:
                    shutil.copy(tmp_path, self.grub_default_path)
            finally:
                os.unlink(tmp_path)
                
            # 更新GRUB配置
            self.update_grub_config()
            
        except Exception as e:
            raise RuntimeError(f"更新GRUB配置失败: {str(e)}")

    def _set_next_boot_entry(self, menu_path):
        """设置下次启动条目"""
        try:
            commands_to_try = [
                ['grub-reboot', menu_path],
                ['/usr/sbin/grub-reboot', menu_path]
            ]
            
            success = False
            if os.geteuid() != 0:
                for cmd in commands_to_try:
                    try:
                        subprocess.run(['pkexec'] + cmd, check=True)
                        success = True
                        break
                    except (subprocess.CalledProcessError, FileNotFoundError):
                        try:
                            subprocess.run(['sudo'] + cmd, check=True)
                            success = True
                            break
                        except (subprocess.CalledProcessError, FileNotFoundError):
                            continue
            else:
                for cmd in commands_to_try:
                    try:
                        subprocess.run(cmd, check=True)
                        success = True
                        break
                    except (subprocess.CalledProcessError, FileNotFoundError):
                        continue
            
            if not success:
                raise RuntimeError("无法设置下次启动条目")
                
        except Exception as e:
            raise RuntimeError(f"设置下次启动条目失败: {str(e)}")

    def _clean_grub_entry_id(self, entry_id):
        """
        清理GRUB条目ID，确保它是一个有效的标识符
        """
        # 如果entry_id是复杂字符串（包含引号、特殊字符等），尝试提取简单版本
        if isinstance(entry_id, str):
            # 如果包含逗号，可能是完整菜单项，提取第一部分
            if ',' in entry_id:
                entry_id = entry_id.split(',')[0].strip()
            
            # 移除可能的引号
            entry_id = entry_id.strip('"\'')
            
            # 如果是数字，直接返回数字（GRUB索引方式）
            if entry_id.isdigit():
                return entry_id
            
            # 如果太长或者包含特殊字符，考虑使用索引方式
            if len(entry_id) > 100 or any(c in entry_id for c in ['--class', '$menuentry_id_option']):
                # 返回简单的索引方式
                return "0"  # 默认启动第一个条目
        
        return entry_id

    def update_grub_config(self):
        """更新GRUB配置"""
        try:
            # 首先尝试使用 update-grub (Debian/Ubuntu 系统)
            commands_to_try = [
                ['update-grub'],
                ['grub-mkconfig', '-o', self.grub_cfg_path],
                ['/usr/sbin/grub-mkconfig', '-o', self.grub_cfg_path]
            ]
            
            if os.geteuid() != 0:
                # 需要提权的情况
                for cmd in commands_to_try:
                    try:
                        subprocess.run(['pkexec'] + cmd, check=True)
                        return True
                    except (subprocess.CalledProcessError, FileNotFoundError):
                        try:
                            subprocess.run(['sudo'] + cmd, check=True)
                            return True
                        except (subprocess.CalledProcessError, FileNotFoundError):
                            continue  # 尝试下一个命令
                raise PermissionError("无法更新GRUB配置")
            else:
                # 已经是root权限
                for cmd in commands_to_try:
                    try:
                        subprocess.run(cmd, check=True)
                        return True
                    except (subprocess.CalledProcessError, FileNotFoundError):
                        continue  # 尝试下一个命令
                raise RuntimeError("无法更新GRUB配置")
                
        except Exception as e:
            print(f"更新GRUB配置失败: {e}")
            raise RuntimeError(f"无法更新GRUB配置: {e}")

    def show_message(self, title, message, msg_type='info'):
        """显示消息对话框"""
        if msg_type == 'error':
            messagebox.showerror(title, message)
        elif msg_type == 'warning':
            messagebox.showwarning(title, message)
        else:
            messagebox.showinfo(title, message)

    def refresh_all(self):
        """刷新所有数据"""
        try:
            self.refresh_install()
        except Exception as e:
            self.install_status_var.set(f"刷新失败: {str(e)}")
            self.root.update_idletasks()

def main():
    root = tk.Tk()
    app = KernelManagementGUI(root)
    
    # 检查是否为root用户或具有sudo权限 (使用主窗口的60%尺寸)
    if os.geteuid() != 0:
        app.show_message("权限提醒", "某些操作可能需要root权限", 'warning')
    root.mainloop()

if __name__ == "__main__":
    main()